#ifndef XICT_DRIVER_TASK_PERIODIC_TASK_H
#define XICT_DRIVER_TASK_PERIODIC_TASK_H

#include "xict_common/utils/utils_timer.h"
#include "xict_driver/utils/utils_error.h"
#include <cmath>
#include <functional>
#include <string>
#include <sys/timerfd.h>
#include <thread>
#include <unistd.h>
#include <vector>

namespace xict_driver {
    namespace task {
        class PeriodicTaskManager;

        /**
         * @brief  The base class of a periodic task, a single periodic task
         * which will call run() at the given frequency Adapted from
         * Cheetah-Software
         */
        class PeriodicTask {
        public:
            /**
             * @brief Construct a new Periodic Task object
             *
             * @param _task_manager
             * @param _period
             * @param _name
             */
            PeriodicTask(PeriodicTaskManager* _task_manager, float _period,
                         std::string _name);

            /**
             * @brief Start the  task
             *
             */
            void Start();

            /**
             * @brief Stop the task
             *
             */
            void Stop();

            /**
             * @brief print task status
             *
             */
            void PrintStatus();

            /**
             * @brief Clear  member variables
             *
             */
            void ClearMax();

            /**
             * @brief  Is the task running too slow
             *
             * @return true
             * @return false
             */
            bool IsSlow();

            /**
             * @brief Is the task is abnormal
             */
            bool IsAbnormal();

            /**
             * @brief Register exception callback function
             *
             * @param cb_excep
             */
            void RegExceptionCallback(
                const std::function<void(const xict_driver::utils::ErrorInfo&)>&
                    cb_excep);

            /**
             * @brief  initialization
             *
             */
            virtual void Init() = 0;

            /**
             * @brief run the task
             *
             */
            virtual void Run() = 0;

            /**
             * @brief Clean up
             *
             */
            virtual void Cleanup() = 0;

            /**
             * @brief Destroy the Periodic Task object
             *
             */
            virtual ~PeriodicTask() {
                Stop();
            }

            /**
             * @brief  Get the desired period for the task
             *
             * @return float
             */
            float GetPeriod() {
                return period_;
            }

            /**
             * @brief Get how long the most recent run took
             *
             * @return float
             */
            float GetRuntime() {
                return last_runtime_;
            }

            /**
             * @brief Get the Max Period object
             *
             * @return float
             */
            float GetMaxPeriod() {
                return max_period_;
            }

            /**
             * @brief Get the Max Runtime object
             *
             * @return float
             */
            float GetMaxRuntime() {
                return max_runtime_;
            }

            /**
             * @brief Get the name object
             */
            std::string GetName() {
                return name_;
            }

        private:
            /**
             * @brief the main function of the task
             *
             */
            void LoopFunction();

            /// @brief the period of the task
            float period_;
            /// @brief the running flag of the task
            volatile bool running_flag_ = false;
            /// @brief the abnormal flag of the task
            bool abnormal_flag_ = false;

            /// @brief  last runing time
            float last_runtime_ = 0;
            /// @brief  last period time
            float last_period_time_ = 0;
            /// @brief  max period
            float max_period_ = 0;
            /// @brief  max run time
            float max_runtime_ = 0;
            /// @brief  the name of the task
            std::string name_;
            /// @brief  the thread of the taskl
            std::thread thread_;

            /// @brief exception callback function
            std::function<void(const xict_driver::utils::ErrorInfo&)>
                cb_exception_;
        };

        /**
         * A collection of periodic tasks which can be monitored together
         * Adapted from Cheetah-Software
         */
        class PeriodicTaskManager {
        public:
            /**
             * @brief Construct a new Periodic Task Manager object
             *
             */
            PeriodicTaskManager() = default;

            /**
             * @brief Destroy the Periodic Task Manager object
             *
             */
            ~PeriodicTaskManager();

            /**
             * @brief Add task to task manager
             *
             * @param task
             */
            void AddTask(PeriodicTask* task);

            /**
             * @brief Print task status
             *
             */
            void PrintStatus();

            /**
             * @brief print the slow tasks status
             *
             */
            void PrintStatusOfSlowTasks();

            /**
             * @brief start all task
             */
            void StartAll();

            /**
             * @brief stop all task
             *
             */
            void StopAll();

            /**
             * @brief Get the number of the tasks
             */
            size_t GetTaskNum();

            /**
             * @brief monitor the tasks
             */
            void MonitorTasks();

        private:
            /// @brief  the vector of the task
            std::vector<xict_driver::task::PeriodicTask*> tasks_;
        };
    }   // namespace task
}   // namespace xict_driver

#endif